#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <regex>
#include <sys/stat.h>
#include "../server.hpp"

#define DEFAULT_TIMEROUT 10

std::unordered_map<int, std::string> _statu_msg = 
{
    {100,  "Continue"},
    {101,  "Switching Protocol"},
    {102,  "Processing"},
    {103,  "Early Hints"},
    {200,  "OK"},
    {201,  "Created"},
    {202,  "Accepted"},
    {203,  "Non-Authoritative Information"},
    {204,  "No Content"},
    {205,  "Reset Content"},
    {206,  "Partial Content"},
    {207,  "Multi-Status"},
    {208,  "Already Reported"},
    {226,  "IM Used"},
    {300,  "Multiple Choice"},
    {301,  "Moved Permanently"},
    {302,  "Found"},
    {303,  "See Other"},
    {304,  "Not Modified"},
    {305,  "Use Proxy"},
    {306,  "unused"},
    {307,  "Temporary Redirect"},
    {308,  "Permanent Redirect"},
    {400,  "Bad Request"},
    {401,  "Unauthorized"},
    {402,  "Payment Required"},
    {403,  "Forbidden"},
    {404,  "Not Found"},
    {405,  "Method Not Allowed"},
    {406,  "Not Acceptable"},
    {407,  "Proxy Authentication Required"},
    {408,  "Request Timeout"},
    {409,  "Conflict"},
    {410,  "Gone"},
    {411,  "Length Required"},
    {412,  "Precondition Failed"},
    {413,  "Payload Too Large"},
    {414,  "URI Too Long"},
    {415,  "Unsupported Media Type"},
    {416,  "Range Not Satisfiable"},
    {417,  "Expectation Failed"},
    {418,  "I'm a teapot"},
    {421,  "Misdirected Request"},
    {422,  "Unprocessable Entity"},
    {423,  "Locked"},
    {424,  "Failed Dependency"},
    {425,  "Too Early"},
    {426,  "Upgrade Required"},
    {428,  "Precondition Required"},
    {429,  "Too Many Requests"},
    {431,  "Request Header Fields Too Large"},
    {451,  "Unavailable For Legal Reasons"},
    {501,  "Not Implemented"},
    {502,  "Bad Gateway"},
    {503,  "Service Unavailable"},
    {504,  "Gateway Timeout"},
    {505,  "HTTP Version Not Supported"},
    {506,  "Variant Also Negotiates"},
    {507,  "Insufficient Storage"},
    {508,  "Loop Detected"},
    {510,  "Not Extended"},
    {511,  "Network Authentication Required"}
};

std::unordered_map<std::string, std::string> _mime_msg = 
{
    {".aac",        "audio/aac"},
    {".abw",        "application/x-abiword"},
    {".arc",        "application/x-freearc"},
    {".avi",        "video/x-msvideo"},
    {".azw",        "application/vnd.amazon.ebook"},
    {".bin",        "application/octet-stream"},
    {".bmp",        "image/bmp"},
    {".bz",         "application/x-bzip"},
    {".bz2",        "application/x-bzip2"},
    {".csh",        "application/x-csh"},
    {".css",        "text/css"},
    {".csv",        "text/csv"},
    {".doc",        "application/msword"},
    {".docx",       "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
    {".eot",        "application/vnd.ms-fontobject"},
    {".epub",       "application/epub+zip"},
    {".gif",        "image/gif"},
    {".htm",        "text/html"},
    {".html",       "text/html"},
    {".ico",        "image/vnd.microsoft.icon"},
    {".ics",        "text/calendar"},
    {".jar",        "application/java-archive"},
    {".jpeg",       "image/jpeg"},
    {".jpg",        "image/jpeg"},
    {".js",         "text/javascript"},
    {".json",       "application/json"},
    {".jsonld",     "application/ld+json"},
    {".mid",        "audio/midi"},
    {".midi",       "audio/x-midi"},
    {".mjs",        "text/javascript"},
    {".mp3",        "audio/mpeg"},
    {".mpeg",       "video/mpeg"},
    {".mpkg",       "application/vnd.apple.installer+xml"},
    {".odp",        "application/vnd.oasis.opendocument.presentation"},
    {".ods",        "application/vnd.oasis.opendocument.spreadsheet"},
    {".odt",        "application/vnd.oasis.opendocument.text"},
    {".oga",        "audio/ogg"},
    {".ogv",        "video/ogg"},
    {".ogx",        "application/ogg"},
    {".otf",        "font/otf"},
    {".png",        "image/png"},
    {".pdf",        "application/pdf"},
    {".ppt",        "application/vnd.ms-powerpoint"},
    {".pptx",       "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
    {".rar",        "application/x-rar-compressed"},
    {".rtf",        "application/rtf"},
    {".sh",         "application/x-sh"},
    {".svg",        "image/svg+xml"},
    {".swf",        "application/x-shockwave-flash"},
    {".tar",        "application/x-tar"},
    {".tif",        "image/tiff"},
    {".tiff",       "image/tiff"},
    {".ttf",        "font/ttf"},
    {".txt",        "text/plain"},
    {".vsd",        "application/vnd.visio"},
    {".wav",        "audio/wav"},
    {".weba",       "audio/webm"},
    {".webm",       "video/webm"},
    {".webp",       "image/webp"},
    {".woff",       "font/woff"},
    {".woff2",      "font/woff2"},
    {".xhtml",      "application/xhtml+xml"},
    {".xls",        "application/vnd.ms-excel"},
    {".xlsx",       "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
    {".xml",        "application/xml"},
    {".xul",        "application/vnd.mozilla.xul+xml"},
    {".zip",        "application/zip"},
    {".3gp",        "video/3gpp"},
    {".3g2",        "video/3gpp2"},
    {".7z",         "application/x-7z-compressed"}
};

class Util
{
public:
    // 字符串分割函数
    static size_t Split(const std::string& src,  const std::string& sep, std::vector<std::string>* arry)
    {
        size_t offset = 0;
        while(offset <  src.size())
        {
            // 在src字符串偏移量位offset的位置, 开始向后查找sep字符/字符串, 并返回查找到的位置
            size_t pos = src.find(sep, offset);
            if(pos == std::string::npos)
            {
                if(pos == src.size())  break;
                arry->push_back(src.substr(offset));
                return arry->size();
            }
            // 当前的字符串是空的, 不计入
            if(pos == offset)
            {
                offset = pos + sep.size();
                continue;
            }

            arry->push_back(src.substr(offset, pos - offset));
            offset = pos + sep.size();
        }

        return arry->size();
    }

    // 读取文件的所有内容, 将读取到的内容放到一个string中
    static bool ReadFile(const std::string& filename, std::string* buf)
    {
        std::ifstream ifs(filename, std::ios::binary);
        if(ifs.is_open() == false)
        {
            DBG_LOG("readfile: open %s file failed!", filename.c_str());
            return false;
        }
        size_t fsize = 0;
        // 跳转读写位置到末尾
        ifs.seekg(0, ifs.end);
        // 获取当前读写位置相对于起始位置的偏移量, 从末尾偏移刚好就是文件大小
        fsize = ifs.tellg();
        // 跳转到起始位置
        ifs.seekg(0, ifs.beg);
        // 开辟文件大小的空间
        buf->resize(fsize);
        ifs.read(&(*buf)[0], fsize);
        if(ifs.good() == false)
        {
            DBG_LOG("read %s file failed!", filename.c_str());
            ifs.close();
            return false;
        }

        ifs.close();
        return true;
    }

    // 向文件写入数据
    static bool WriteFile(const std::string& filename, const std::string& buf)
    {
        std::ofstream ofs(filename, std::ios::binary | std::ios::trunc);
        if(ofs.is_open() == false)
        {
            DBG_LOG("writefile: open %s file failed!", filename.c_str());
            return false;
        }
        ofs.write(buf.c_str(), buf.size());
        if(ofs.good() == false)
        {
            DBG_LOG("write %s file failed!", filename.c_str());
            ofs.close();
            return false;
        }

        ofs.close();
        return false;
    }

    // URL编码
    static std::string  UrlEncode(const std::string& url, bool convert_space_to_plus)
    {
        std::string res;
        for(auto& e: url)
        {
            // 在RFCC3986文档中规定的URL绝对不编码字符有 . ~ - _ 字母和数字
            if(e == '.' || e == '-' || e == '_' || e ==  '~' || isalnum(e))
            {
                res += e;
                continue;
            }
            // W3C中规定, 空格必须编码为 +
            if(e == ' ' &&  convert_space_to_plus == true)
            {
                res += '+';
                continue;
            }
            // 剩下的字符都是需要编码成为 %HH 格式
            char tem[4] = {0};
            snprintf(tem, 4, "%%%02X", e);
            res += tem;
        }
        return res;
    }

    // URL解码
    static char HexToI(char c)
    {
        if(c >= '0' && c <= '9')  return c - '0';
        else if(c >= 'a' && c <= 'z')  return c - 'a' + 10;
        else if(c >= 'A' && c <= 'Z')  return c - 'A' + 10;
        else  return -1;
    }

    static std::string UrlDecode(const std::string& url, bool convert_plus_to_space)
    {
        // 遇到了%, 就将其后面的两个字符转换为数字
        // 然后将第一个数字左移四位, 再加上第二个数字
        std::string res;
        for(int i = 0; i < url.size(); i++)
        {
            if(url[i] == '+' && convert_plus_to_space == true)
            {
                res += ' ';
                continue;
            }
            if(url[i] == '%' && i + 2 < url.size())
            {
                char v1 = HexToI(url[i+1]);
                char v2 = HexToI(url[i+2]);
                char v = v1 * 16 + v2;
                res += v;
                i += 2;
                continue;
            }
            res += url[i];
        }
        return res;
    }

    // 响应状态码的描述信息获取
    static std::string StatuDesc(int statu) 
    {
        auto it = _statu_msg.find(statu);
        if (it != _statu_msg.end()) 
        {
            return it->second;
        }
        return "Unknow";
    }
    // 根据文件后缀获取文件mime
    static std::string ExtMime(const std::string &filename) 
    {
        // a.b.txt  先获取文件扩展名
        size_t pos = filename.find_last_of('.');
        if (pos == std::string::npos) {
            return "application/octet-stream";
        }
        //根据扩展名，获取mime
        std::string ext = filename.substr(pos);
        auto it = _mime_msg.find(ext);
        if (it == _mime_msg.end()) {
            return "application/octet-stream";
        }
        return it->second;
    }

    // 判读一个文件是否是目录
    static bool IsDirectory(const std::string &filename) 
    {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0) 
        {
            return false;
        }
         return S_ISDIR(st.st_mode);
    }

    // 判读一个文件是否是一个普通文件
    static bool IsRegular(const std::string &filename) 
    {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0) 
        {
            return false;
        }
        return S_ISREG(st.st_mode);
    }

    // http请求的资源路径有效性判断
    static bool ValidPath(const std::string &path) 
    {
        //思想：按照/进行路径分割，根据有多少子目录，计算目录深度，有多少层，深度不能小于0
        std::vector<std::string> subdir;
        Split(path, "/", &subdir);
        int level = 0;
        for (auto &dir : subdir) 
        {
            if (dir == "..") 
            {
                level--; //任意一层走出相对根目录，就认为有问题
                if (level < 0) return false;
                continue;
            }
            level++;
        }
        return true;
    }

};

class HttpRequest
{
public:
    std::string _method;  // 请求方法
    std::string _path;  // 资源路径
    std::string _version; // 协议版本
    std::string _body; // 请求正文
    std::smatch _matches; // 资源路径的正则提取数据
    std::unordered_map<std::string, std::string> _headers; // 头部字段
    std::unordered_map<std::string, std::string> _params; // 查询字符串

public:
    HttpRequest() :_version("HTTP/1.1")
    {}

    // 重置
    void ReSet()
    {
        _method.clear();
        _path.clear();
        _version = "HTTP/1.1";
        _body.clear();
        _headers.clear();
        _params.clear();

        std::smatch mathces;
        _matches.swap(mathces);
    }

    // 插入头部字段
    void SetHeader(const std::string& key, const std::string& val)
    {
        _headers.insert({key, val});
    }

    // 判断是否存在指定头部字段
    bool HasHeader(const std::string& key) const
    {
        auto iter = _headers.find(key);
        if(iter == _headers.end())
        {
            return false;
        }
        return true;
    }

    // 获取指定头部字段的值
    std::string GetHeader(const std::string& key) const
    {
        auto iter = _headers.find(key);
        if(iter == _headers.end())
        {
            return "";
        }
        return iter->second;
    }

    // 插入查询字符串
    void SetParam(const std::string& key, const std::string& val)
    {
        _params.insert({key, val});
    }

    // 判读是否有某个指定的查询字符串
    bool HasParam(const std::string& key) const
    {
        auto iter = _params.find(key);
        if(iter == _params.end())
        {
            return false;
        }
        return true;
    }

    // 获取指定的查询字符串
    std::string GetParam(const std::string& key) const
    {
        auto iter = _params.find(key);
        if(iter == _params.end())
        {
            return "";
        }
        return iter->second;
    }

    // 获取正文长度
    size_t GetContentLength() const
    {
        // Content-Length:123456\r\n
        bool res = HasHeader("Content-Length");
        if(res == false)  return 0;

        std::string clen = GetHeader("Content-Length");
        return std::stol(clen);
    }

    // 是否是短连接
    bool Close() const
    {
        // 短连接: 没有Connection字段, 或者Connection字段的值为false
        // 长连接: Connection字段的值为keep-alive
        if(HasHeader("Connection") && GetHeader("Connection") == "keep-alive")
        {
            return false;
        }
        return true;
    }
};

class HttpResponse
{
public:
    int _status;  // 状态码
    bool _redirect_flag;  // 重定向标志
    std::string _body; // 响应正文
    std::string _redierct_url; // 重定向url
    std::unordered_map<std::string, std::string> _headers; // 响应报头

public:
    HttpResponse()
        :_status(200), _redirect_flag(false)
    {}

    HttpResponse(int status)
        :_status(status), _redirect_flag(false)
    {}

    // 重置
    void ReSet()
    {
        _status = 200;
        _redirect_flag = false;
        _body.clear();
        _redierct_url.clear();
        _headers.clear();
    }

    // 插入头部字段
    void SetHeader(const std::string& key, const std::string& val)
    {
        _headers.insert({key, val});
    }

    // 判段是否存在指定头部字段
    bool HasHeader(const std::string& key)const
    {
        auto iter = _headers.find(key);
        if(iter == _headers.end())
        {
            return false;
        }
        return true;
    }

    // 获取指定头部字段的值
    std::string GetHeader(const std::string& key)const
    {
        auto iter = _headers.find(key);
        if(iter == _headers.end())
        {
            return "";
        }
        return iter->second;
    }

    // 响应正文的设置
    void SetContent(const std::string& body, const std::string& type = "text/html")
    {
        _body = body;
        SetHeader("Content-Type", type);

    }
    
    // 重定向的设置
    void SetRedirect(const std::string& url, int status = 302)
    {
        _status = status;
        _redierct_url = url;
        _redirect_flag = true;
    }
    
    // 是否是短连接
    bool Close() const
    {
        // 短连接: 没有Connection字段, 或者Connection字段的值为false
        // 长连接: Connection字段的值为keep-alive
        if(HasHeader("Connection") && GetHeader("Connection") == "keep-alive")
        {
            return false;
        }
        return true;
    }
};

// 请求接收上下文模块
#define MAX_LINE 8196
typedef enum
{
    RECEIVE_HTTP_ERROR,
    RECEIVE_HTTP_LINE,
    RECEIVE_HTTP_HEAD,
    RECEIVE_HTTP_BODY,
    RECEIVE_HTTP_OVER
}HttpReceiveStatus;

class HttpContext
{
private:
    int _response_status; // 响应状态码
    HttpReceiveStatus _receive_status; // 接收状态
    HttpRequest _request; // 已经接收并处理的请求信息

private:
    bool ParseHttpLine(const std::string& line)
    {
        std::smatch matches;
        std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?", std::regex::icase);
        // std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))?(HTTP/1\\.[01])(?:\n|\r\n)?", std::regex::icase);

        bool res = std::regex_match(line, matches, e);
        if(res == false)
        {
            DBG_LOG("ParseHttpLine error!");
            _receive_status = RECEIVE_HTTP_ERROR;
            _response_status = 400; // BAD REQUEST
            return false;
        }

        // 0 : GET /csdn/login?user=muyu&pass=112435 HTTP/1.1
        // 1 : GET
        // 2 : /csdn/login
        // 3 : user=muyu&pass=112435 
        // 4 : HTTP/1.1
        _request._method = matches[1];
        // 转大写
        std::transform(_request._method.begin(), _request._method.end(), _request._method.begin(), ::toupper);
        _request._path = Util::UrlDecode(matches[2], false);
        _request._version = matches[4];
        // 查询字符串的获取与处理
        // 查询字符串的格式为: key=val&key=val... ...
        // ==> 所以查询字符串的处理为: 1.先以&符号进行分割, 2.再以=符号进行分割 3. 再进行解码
        std::vector<std::string> query_string;
        std::string tem = matches[3];
        // 1.先以&符号进行分割
        Util::Split(tem, "&", &query_string);
        // 2.再以=符号进行分割
        for(auto& str : query_string)
        {
            size_t pos = str.find("=");
            if(pos == std::string::npos)
            {
                _receive_status = RECEIVE_HTTP_ERROR;
                _response_status = 400; // BAD REQUEST
                return false;
            }
            // 3.再进行解码
            std::string key = Util::UrlDecode(str.substr(0, pos), true);
            std::string val = Util::UrlDecode(str.substr(pos+1), true);
            // 插入查询字符串
            _request.SetParam(key, val);
        }

        return true;
    }

    bool ReceiveHttpLine(Buffer* buf)
    {
        if(_receive_status !=  RECEIVE_HTTP_LINE)  return false;

        // 1.获取一行数据
        std::string line = buf->GetLineAndPop();
        // 2.对获取上来的一行数据做差错处理 -- 数据不足一行, 或者数据过大
        // a.数据不足一行
        if(line.size() == 0)
        {
            // 不足一行, 但是数据很长 说明是有问题的
            if(buf->ReadAbleSize() > MAX_LINE)
            {
                _receive_status = RECEIVE_HTTP_ERROR;
                _response_status = 414; // URI TOO LONG
                return false;
            }
            // 不足一行, 但是数据也不是很多, 那就继续等待数据
            return true;
        }
        // b.数据过大
        if(line.size() > MAX_LINE)
        {
            _receive_status = RECEIVE_HTTP_ERROR;
            _response_status = 414; // URI TOO LONG
            return false;
        }

        // 3.正常,交给解析
        bool res = ParseHttpLine(line);
        if(res == false)  return false;

        // 首行处理完毕, 进入头部处理阶段
        _receive_status = RECEIVE_HTTP_HEAD;
        return true;
    }

    bool ParseHttpHeader(std::string& line)
    {
        // 先去掉末尾的\r\n
        if(line.back() == '\n')  line.pop_back();
        if(line.back() == '\r')  line.pop_back();

        size_t pos = line.find(": ");
        if(pos == std::string::npos)
        {
            _receive_status = RECEIVE_HTTP_ERROR;
            _response_status = 400; // BAD REQUEST
            return false;
        }

        std::string key = line.substr(0, pos);
        std::string val = line.substr(pos + 2);
        // 插入头部字段
        _request.SetHeader(key, val);

        return true;
    }

    bool ReceiveHttpHeader(Buffer* buf)
    {
        if(_receive_status != RECEIVE_HTTP_HEAD)  return false;

        // 头部的格式是: key:val\r\nkey:val\r\n... ...
        // ==> 所以只需要一行一行取出数据, 直到遇到空行为止
        while(1)
        {
            // 1.获取一行数据
            std::string line = buf->GetLineAndPop();
            // 2.对获取上来的一行数据做差错处理 -- 数据不足一行, 或者数据过大
            // a.数据不足一行
            if(line.size() == 0)
            {
                // 不足一行, 但是数据很长 说明是有问题的
                if(buf->ReadAbleSize() > MAX_LINE)
                {
                    _receive_status = RECEIVE_HTTP_ERROR;
                    _response_status = 414; // URI TOO LONG
                    return false;
                }
                // 不足一行, 但是数据也不是很多, 那就继续等待数据
                return true;
            }
            // b.数据过大
            if(line.size() > MAX_LINE)
            {
                _receive_status = RECEIVE_HTTP_ERROR;
                _response_status = 414; // URI TOO LONG
                return false;
            }

            // 读到空行
            if(line == "\n" || line =="\r\n")  break;

            // 3.正常,交给解析
            bool res = ParseHttpHeader(line);
            if(res == false)  return false;
        }

        // 头部处理完毕, 进入正文处理阶段
        _receive_status = RECEIVE_HTTP_BODY;
        return true;
    }

    bool ReceiveHttpBody(Buffer* buf)
    {
        if(_receive_status != RECEIVE_HTTP_BODY)  return false;

        // 1.获取正文长度
        size_t content_len = _request.GetContentLength();
        // 没有正文, 则请求解析完毕
        if(content_len == 0)
        {
            _receive_status = RECEIVE_HTTP_OVER;
            return true;
        }

        // 2.当前已经接收了多少正文 ==> 实际还需要接收的数据长度
        //   当前已经接收了正文的长度: _request._body.size(),  正文长度: content_len
        //   ==> 实际很需要接收的数据长度 = content_length - _request._body.size();
        size_t real_len = content_len - _request._body.size();

        // 3.接收正文放到body中, 但是也要考虑当前缓冲区中的数据, 是否是全部的正文(有可能正好, 也有可能少了)
        //   3.1接收缓冲区中的数据(ReadAbleSize()), 包含了当前请求的所有正文, 则取出全部的数据
        if(buf->ReadAbleSize() >= real_len)
        {
            _request._body.append(buf->ReadPosition(), real_len);
            buf->MoveReadOffset(real_len);
            
            _receive_status = RECEIVE_HTTP_OVER;
            return true;
        }
        //   3.2接收缓冲区中的数据, 无法满足当前正文的需要 -- 数据不足 --> 则需要1. 取出数据, 2.等待新的数据的到来
        _request._body.append(buf->ReadPosition(), buf->ReadAbleSize());
        buf->MoveReadOffset(buf->ReadAbleSize());
        return true;
    }

public:
    HttpContext()
        :_response_status(200), _receive_status(RECEIVE_HTTP_LINE)
    {}

    void ReSet()
    {
        _response_status = 200;
        _receive_status = RECEIVE_HTTP_LINE;
        _request.ReSet();
    }

    // 返回响应状态
    int ResponseStatus()
    {
        return _response_status;
    }

    // 返回接收状态
    HttpReceiveStatus& ReceiveStatus()
    {
        return _receive_status;
    }

    // 返回请求信息
    HttpRequest& Request()
    {
        return _request;
    }

    // 接收并解析HTTP请求
    void ReceiveHttpRequest(Buffer* buf)
    {
        // 不同的状态, 做不同的事情
        // tips: 不要break, 这是一个连贯的过程, 而不需要退出等待新的数据
        switch(_receive_status)
        {
            case RECEIVE_HTTP_LINE: ReceiveHttpLine(buf);
            case RECEIVE_HTTP_HEAD: ReceiveHttpHeader(buf);
            case RECEIVE_HTTP_BODY: ReceiveHttpBody(buf);
        }
        
        return;
    }
};

class HttpServer
{
private:
    using Handler = std::function<void(const HttpRequest&, HttpResponse*)>;
    using HandlerType = std::vector<std::pair<std::regex, Handler>>;
    HandlerType _get_route_table;
    HandlerType _post_route_table;
    HandlerType _put_route_table;
    HandlerType _delete_route_table;
    std::string _basedir; // 静态资源根目录
    TcpServer _server; // 高效能tcp服务器

private:
    void ErrorHandler(const HttpRequest& request, HttpResponse* response)
    {
        // 1.组织一个错误展示页面
        std::string body;
        body += "<html>";
        body += "<head>";
        body += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
        body += "</head>";
        body += "<body>";
        body += "<h1>";
        body += std::to_string(response->_status);
        body += " ";
        body += Util::StatuDesc(response->_status);
        body += "</h1>";
        body += "</body>";
        body += "</html>";

        // 2.将页面数据, 当做响应正文, 放入到response中
        response->SetContent(body, "text/html");
    }
    
    // 将HttpResponse中的要素按照http协议格式进行组织, 发送
    void WriteResponse(const PtrConnection& conn, const HttpRequest& request, HttpResponse& response)
    {
        // 1.完善头部字段
        if(request.Close() == true)
        {
            response.SetHeader("Connection", "close");
        }
        else
        {
            response.SetHeader("Connection", "keep-alive");
        }
        if(response._body.empty() == false && response.HasHeader("Content-Length") == false)
        {
            response.SetHeader("Content-Length", std::to_string(response._body.size()));
        }
        if(response._body.empty() == false && response.HasHeader("Content-Type") == false)
        {
            response.SetHeader("Content-Type", "application/octet-stream");
        }
        if(response._redirect_flag == true)
        {
            response.SetHeader("Location", response._redierct_url);
        }

        // 2.将response中的要素, 按照http协议格式进行组织
        std::stringstream response_str;
        response_str << request._version << " " << std::to_string(response._status) << " " << Util::StatuDesc(response._status) << "\r\n";
        for(auto& head : response._headers)
        {
            response_str << head.first << ": " << head.second << "\r\n";
        }
        response_str << "\r\n";
        response_str << response._body;

        // 3.发送数据
        conn->Send(response_str.str().c_str(), response_str.str().size());
    }

    // 功能行请求的分类处理
    void Dispatcher(HttpRequest& request, HttpResponse* response, HandlerType& handlers)
    {
        // 在对应请求方法的路由表中, 查找是否含有对应的处理函数 --> 有则调用, 没有则返回404
        // 路由表中存储的是:功能性请求方法和它对应的处理函数(正则表达式:处理函数)
        // ==> 对请求的资源路径进行正则匹配, 匹配成功就使用对应的处理函数

        for(auto& e : handlers)
        {
            const std::regex& rg = e.first;
            const Handler& functor = e.second;
            bool res = std::regex_match(request._path, request._matches, rg);
            if(res == false)
            {
                continue;
            }
            // 传入请求信息, 空的response, 和执行处理函数
            return functor(request, response);
        }
        response->_status = 404;
    }

    // 静态资源的请求处理 -- 将静态资源文件的数据读取出来, 放到response的_body, 并设置mime
    void FileHandler(const HttpRequest& request, HttpResponse* response)
    {
        std::string request_path = _basedir + request._path;
        if(request._path.back() == '/')
        {
            request_path += "index.html";
        }

        bool res = Util::ReadFile(request_path, &response->_body);
        if(res == false)  return ;

        std::string mime = Util::ExtMime(request_path);
        response->SetHeader("Content-Type", mime);
        return ;
    }

    // 给TcpServer设置协议上下文
    void OnConnected(const PtrConnection& conn)
    {
        conn->SetContext(HttpContext());
        DBG_LOG("new connection > %p", conn.get());
    }

    // 缓冲区数据解析 + 处理
    void OnMessage(const PtrConnection& conn, Buffer* buf)
    {
        while(buf->ReadAbleSize())
        {
            // 1.获取上下文
            HttpContext* context = conn->GetContext()->get<HttpContext>();

            // 2.通过上下文对缓冲区中的数据进行解析, 并得到HttpRequest对象
            context->ReceiveHttpRequest(buf);
            HttpResponse response(context->ResponseStatus());

            //   1.如果缓冲区中的数据解析出错, 则直接回复 出错响应
            HttpRequest& request = context->Request();
            if(context->ResponseStatus() >= 400)
            {
                // 填充一个错误显示页面数据到response中
                ErrorHandler(request, &response);
                // 组织响应发送给客户端
                WriteResponse(conn, request, response);

                // tips:比较重要 -- 出错了就重置上下文, 并把缓冲区数据清空
                context->ReSet();
                buf->MoveReadOffset(buf->ReadAbleSize());

                // 关闭连接
                conn->Shutdown();
                return;
            }
            //   2.如果解析正常, 且请求已经获取完毕(RECEIVE_HTTP_OVER), 才开始进行处理
            if(context->ReceiveStatus() != RECEIVE_HTTP_OVER) 
            {
                // 当前请求还没有接收完整 --> 先退出, 等待新数据的到来再继续处理
                return;
            }

            // 3.请求路由 + 业务处理
            Route(request, &response);

            // 4.对HttpResponse进行组织并发送
            WriteResponse(conn, request, response);

            // 5.重置上下文
            context->ReSet();

            // 6.根据长短连接, 判断是否关闭连接或者继续处理
            if(response.Close() == true)  conn->Shutdown();
        }
    }
    
    bool IsFileHandler(const HttpRequest& request)
    {
        // 1.必须设置了静态资源根目录
        if(_basedir.empty())  return false;

        // 2.请求方法, 必须是GET/HEAD
        if(request._method != "GET" && request._method != "HEAD")  return false;

        // 3.请求的资源路径必须是一个合法路径
        if(Util::ValidPath(request._path) == false)  return false;

        // 4.请求的资源必须存在, 并且是一个普通文件
        //  纯根目录要注意, 这种情况给后边默认追加一个 index.html (表示首页)
        std::string request_path = _basedir + request._path;
        if(request._path.back() == '/')
        {
            request_path += "index.html";
        }
        if(Util::IsRegular(request_path) == false)
        {
            return false;
        }

        return true;
    }

    void Route(HttpRequest& request, HttpResponse* response)
    {
        // 对请求进行分辨, 是一个静态资源请求, 还是一个功能性请求
        
        // 1.静态资源请求, 需要进行静态资源的处理
        if(IsFileHandler(request) == true)
        {
            return FileHandler(request, response);
        }

        // 2.功能性请求, 需要通过几个路由表来确定是否有处理函数
        if(request._method == "GET" || request._method == "HEAD")
        {
            return Dispatcher(request, response, _get_route_table);
        }
        else if(request._method == "POST")
        {
            return Dispatcher(request, response, _post_route_table);
        }
        else if(request._method == "PUT")
        {
            return Dispatcher(request, response, _put_route_table);
        }
        else if(request._method == "DELETE")
        {
            return Dispatcher(request, response, _delete_route_table);
        }

        // 3.既不是静态资源请求, 也没有设置功能性请求的处理函数, 则返回405
        response->_status = 405; // Method Not Allowed
        return;
    }

public:
    HttpServer(int port, int timerout = DEFAULT_TIMEROUT)
        :_server(port)
    {
        // 启动非活跃定时销毁任务
        _server.EnableInactiveRelease(timerout);
        _server.SetConectedCallback(std::bind(&HttpServer::OnConnected, this, std::placeholders::_1));
        _server.SetMessageCallback(std::bind(&HttpServer::OnMessage, this, std::placeholders::_1, std::placeholders::_2));
    }

    void SetBaseDir(const std::string& path)
    {
        assert(Util::IsDirectory(path) == true);
        _basedir = path;
    }

    // 设置/添加, 正则表达式的请求与处理函数的映射关系
    void Get(const std::string& pattern, const Handler& handler)
    {
        _get_route_table.push_back({std::regex(pattern), handler});
    }

    void Post(const std::string& pattern, const Handler& handler)
    {
        _post_route_table.push_back({std::regex(pattern), handler});
    }

    void Put(const std::string& pattern, const Handler& handler)
    {
        _put_route_table.push_back({std::regex(pattern), handler});
    }

    void Delete(const std::string& pattern, const Handler& handler)
    {
        _delete_route_table.push_back({std::regex(pattern), handler});
    }

    void SetThreadCount(int count)
    {
        _server.SetThreadCount(count);
    }

    void Listen()
    {
        _server.Start();
    }

};